using System;
using System.Collections;
using System.Collections.Generic;
using AppEventUtils;
using UnityEngine;

public class BuffHandle : MonoBehaviour
{
    public LinkedList<BuffInfo> buffList = new LinkedList<BuffInfo>();
    // public OrderedEventList event_ls = new OrderedEventList();
    // public Dictionary<string, OrderedEventBase> event_dc = new Dictionary<string, OrderedEventBase>();
    public Dictionary<string, OrderedEventList> event_ls_dc = new Dictionary<string, OrderedEventList>();

    public void add_event_listener(OrderedEventBase event_i, string event_key = null)
    {
        if (event_key == null)
        {
            event_key = event_i.ToString();
        }

        if (!event_ls_dc.ContainsKey(event_key))
        {
            event_ls_dc.Add(event_key, new OrderedEventList());
        }
        
        if (!event_ls_dc[event_key].HasEvent(event_i))
            event_ls_dc[event_key].AddEvent(event_i);
    }

    public void clear_listener_in_event_ls_dc()
    {
        foreach (var kvp in event_ls_dc)
        {
            var events = kvp.Value.Events;
            
            foreach (var item in events)
            {
                // BdPackage.BdUtils.log("--- remove buff event, EventType: ", item.EventType, "--- event:", item);
                EventManager.instance.remove_event(item, item.EventType);
                
            }

            if (events.Count > 0)
            {
                var event_i = events[0];
                BdPackage.BdUtils.assert(!EventManager.instance.has_event(event_i), $"为啥删除了还包含 event_i? event_i: {event_i}");
            }
        }
        event_ls_dc.Clear();
        buffList.Clear();
    }

    public void deactivate_listener_in_event_ls_dc()
    {
        core_deactivate_listener_in_event_ls_dc(deactivate: true);
    }
    public void activate_listener_in_event_ls_dc()
    {
        core_deactivate_listener_in_event_ls_dc(deactivate: false);
    }
    private void core_deactivate_listener_in_event_ls_dc(bool deactivate = true)
    {
        foreach (var kvp in event_ls_dc)
        {
            var events = kvp.Value.Events;
            
            foreach (var item in events)
            {
                item.active = !deactivate;
            }

        }
    }

    public void show_all_buff_listeners()
    {
        BdPackage.BdUtils.log("--- transform.position.x: ", transform.position.x);
        foreach (var buff_info in buffList)
        {
            BdPackage.BdUtils.log(buff_info.ToString());
        }
        foreach (var kvp in event_ls_dc)
        {
            for (var i = 0; i < kvp.Value.Count; i++)
            {
                var event_i = kvp.Value.Events[i];                
                BdPackage.BdUtils.log($"--- shield --- show_all_buff_listeners ---", event_i.ToString(), ", contains:", EventManager.instance.has_event(event_i));
            }
        }
    }
    // public void clear_listener_in_event_dc()
    // {
    //     foreach (var kvp in event_dc)
    //     {
    //         // BdPackage.BdUtils.log("--- shield (kvp.Value, kvp.Key):", kvp.Value, kvp.Key);
    //         EventManager.instance.remove_event(kvp.Value, kvp.Key);
    //     }    
    // }
    
    private void Update()
    {
        BuffTickAndRemove();
    }

    private void OnMouseUp()
    {
    }

    private void BuffTickAndRemove()
    {
        List<BuffInfo> deleteBuffList = new List<BuffInfo>();
        foreach (var buffInfo in buffList)
        {
            // OnTick
            if (buffInfo.buffData.OnTick != null)
            {
                if (buffInfo.tickTimer < 0)
                {
                    buffInfo.buffData.OnTick.Apply(buffInfo);
                    buffInfo.tickTimer = buffInfo.buffData.tickTime;
                }
                else
                {
                    buffInfo.tickTimer -= Time.deltaTime;
                }
            }
            
            // OnRemove
            if (buffInfo.durationTimer < 0 && buffInfo.buffData.isForever == false)
            {
                deleteBuffList.Add(buffInfo);
            }
            else
            {
                buffInfo.durationTimer -= Time.deltaTime;
            }
        }

        foreach (var buffInfo in deleteBuffList)
        {
            RemoveBuff(buffInfo);
        }
    }

    public void AddBuff(BuffInfo buffInfo)
    {
        BuffInfo findBuffInfo = FindBuff(buffInfo.buffData.id);
        if (findBuffInfo != null)
        {
            // buff已经存在
            if (findBuffInfo.curStack < buffInfo.buffData.maxStack)
            {
                findBuffInfo.curStack++;
                switch (findBuffInfo.buffData.buffUpdateTimeEnum)
                {
                    case BuffUpdateTimeEnum.Add:
                        findBuffInfo.durationTimer += findBuffInfo.buffData.duration;
                        break;
                    case BuffUpdateTimeEnum.Keep:
                        // buffInfo.durationTimer = buffInfo.buffData.duration;
                        break;
                    case BuffUpdateTimeEnum.Replace:
                        findBuffInfo.durationTimer = findBuffInfo.buffData.duration;
                        break;
                }
                findBuffInfo.buffData.OnCreate?.Apply(findBuffInfo);
            }
        }
        else
        {
            // buff 不存在

            buffInfo.durationTimer = buffInfo.buffData.duration;
            // buffInfo.tickTimer = buffInfo.buffData.tickTime;
            buffInfo.buffData.OnCreate?.Apply(buffInfo);
            buffList.AddLast(buffInfo);
            InsertionSortBuffList(buffList);
        }
    }

    public BuffInfo FindBuff(int buffDataID)
    {
        foreach (var buffInfo in buffList)
        {
            if (buffInfo.buffData.id == buffDataID)
            {
                return buffInfo;
            }
        }

        return null;
    }

    public void RemoveBuff(BuffInfo buffInfo)
    {
        switch (buffInfo.buffData.buffRemoveStackUpdateEnum)
        {
            case BuffRemoveStackUpdateEnum.Clear:
                buffInfo.buffData.OnRemove?.Apply(buffInfo);
                buffList.Remove(buffInfo);
                break;
            case BuffRemoveStackUpdateEnum.Reduce:
                buffInfo.curStack--;
                buffInfo.buffData.OnRemove?.Apply(buffInfo);
                
                if (buffInfo.curStack <= 0)
                {
                    buffList.Remove(buffInfo);
                }
                else
                {
                    buffInfo.durationTimer = buffInfo.buffData.duration;
                }
                break;
        }
    }
    
    public void InsertionSortBuffList( LinkedList<BuffInfo> list)
    {
        // Create a new linked list to store the sorted elements
        LinkedList<BuffInfo> sortedList = new LinkedList<BuffInfo>();

        foreach (var buff in list)
        {
            if (sortedList.Count == 0)
            {
                // If the sorted list is empty, simply add the first item
                sortedList.AddFirst(buff);
            }
            else
            {
                // Traverse the sorted list to find the correct position
                LinkedListNode<BuffInfo> current = sortedList.First;
                while (current != null && CompareBuffs(buff, current.Value) > 0)
                {
                    current = current.Next;
                }

                if (current == null)
                {
                    // If we reach the end, add the item at the end
                    sortedList.AddLast(buff);
                }
                else
                {
                    // Insert the item before the current node
                    sortedList.AddBefore(current, buff);
                }
            }
        }

        // Replace the old list with the sorted list
        list = sortedList;
    }

    // Comparison function for BuffInfo
    private int CompareBuffs(BuffInfo a, BuffInfo b)
    {
        if (a.buffData.priority != b.buffData.priority)
        {
            return a.buffData.priority.CompareTo(b.buffData.priority);
        }
        return a.buffData.id.CompareTo(b.buffData.id);
    }
}